import functools


def my_func(a, b=3):
    """Docstring for my_func"""
    print('  called my_func with: ', (a, b))


def show_details(name, f, is_partial=False):
    """show details of a callable object"""
    print('{}: '.format(name))
    print('   object: ', f)
    print('   __name__: ', end=' ')
    try:
        print(f.__name__)
    except AttributeError:
        print('(no __name__)')
    print('   __doc__', repr(f.__doc__))
    return


show_details('my_func', my_func)

p1 = functools.partial(my_func, b=4)
show_details('raw wrapper', p1)

print('Updating wrapper:')
print('  assign: ', functools.WRAPPER_ASSIGNMENTS)
print('  update: ', functools.WRAPPER_UPDATES)
print()

functools.update_wrapper(p1, my_func)
show_details('updated wrapper', p1)
print(my_func.__dict__)
print(my_func.__annotations__, my_func.__qualname__, my_func.__module__)
print(list.__dict__)
print(tuple.__dict__)
